using Microsoft.Extensions.Logging;
using Sage.Http.Core;
using System.Collections.Concurrent;
using System.Diagnostics;

namespace Sage.Http.Factory
{
    /// <summary>
    /// HTTP请求管理器工厂实现，用于创建和管理HTTP请求管理器实例
    /// </summary>
    /// <remarks>
    /// 初始化HTTP请求管理器工厂
    /// </remarks>
    /// <param name="httpClientFactory">HTTP客户端工厂</param>
    /// <param name="loggerFactory">日志工厂（可选）</param>
    public class HttpRequestManagerFactory(
        IHttpClientFactory httpClientFactory,
        ILoggerFactory? loggerFactory = null) : IHttpRequestManagerFactory, IAsyncDisposable
    {
        private readonly IHttpClientFactory _httpClientFactory = httpClientFactory ?? throw new ArgumentNullException(nameof(httpClientFactory));
        private readonly ILoggerFactory? _loggerFactory = loggerFactory;
        private readonly ConcurrentDictionary<string, HttpRequestManager> _managers = new();
        private bool _disposed = false; // 标识是否已释放

        /// <summary>
        /// 获取指定名称的HTTP请求管理器
        /// </summary>
        /// <param name="name">HTTP客户端名称</param>
        /// <returns>HTTP请求管理器</returns>
        public IHttpRequestManager GetHttpRequestManager(string name)
        {
            ObjectDisposedException.ThrowIf(_disposed, this);
            ArgumentException.ThrowIfNullOrEmpty(name);

            return _managers.GetOrAdd(name, CreateManager);
        }

        /// <summary>
        /// 创建HTTP请求管理器
        /// </summary>
        /// <param name="name">HTTP客户端名称</param>
        /// <returns>HTTP请求管理器</returns>
        private HttpRequestManager CreateManager(string name)
        {
            var httpClient = _httpClientFactory.CreateClient(name);
            var logger = _loggerFactory?.CreateLogger<HttpRequestManager>();
            return new HttpRequestManager(httpClient, logger);
        }

        /// <summary>
        /// 释放指定名称的HTTP请求管理器，如果不指定名称则释放所有管理器
        /// </summary>
        /// <param name="name">HTTP客户端名称（可选）</param>
        public void Dispose(string? name)
        {
            ObjectDisposedException.ThrowIf(_disposed, this);
            
            if (string.IsNullOrEmpty(name))
            {
                // 释放所有管理器
                foreach (var managerEntry in _managers)
                {
                    if (_managers.TryRemove(managerEntry.Key, out var manager))
                    {
                        manager.Dispose();
                    }
                }
            }
            else
            {
                // 释放指定名称的管理器
                if (_managers.TryRemove(name, out var manager))
                {
                    manager.Dispose();
                }
            }
        }

        /// <summary>
        /// 释放所有资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 受保护的虚拟Dispose方法
        /// </summary>
        /// <param name="disposing">是否释放托管资源</param>
        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
                return;

            if (disposing)
            {
                // 释放托管资源
                foreach (var managerEntry in _managers)
                {
                    if (_managers.TryRemove(managerEntry.Key, out var manager))
                    {
                        manager.Dispose();
                    }
                }
            }

            _disposed = true;
        }

        /// <summary>
        /// 异步释放
        /// </summary>
        /// <returns></returns>
        public async ValueTask DisposeAsync()
        {
            if (_disposed)
                return;

            _disposed = true;

            // 异步释放所有管理器
            foreach (var managerEntry in _managers.ToArray())
            {
                if (_managers.TryRemove(managerEntry.Key, out var manager))
                {
                    if (manager is IAsyncDisposable asyncManager)
                        await asyncManager.DisposeAsync().ConfigureAwait(false);
                    else
                        manager.Dispose();
                }
            }

            GC.SuppressFinalize(this);
        }
    }
}